package org.ecype.diego;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

import androidx.persistence.ColumnType;
import androidx.persistence.GeneratedValue;
import androidx.persistence.Id;
import androidx.persistence.PersistenceException;

// http://www.sqlite.org/lang_createtable.html
public class Column implements Comparable<Column> {
	private String name;
	private ColumnType type;

	private boolean id;
	private boolean autoincrement;

	private boolean nullable;
	private boolean unique;
	private String defaulfValue;
	private Reference reference;

	public String getName() {
		return name;
	}

	public ColumnType getType() {
		return type;
	}

	public boolean isId() {
		return id;
	}

	public boolean isAutoincrement() {
		return autoincrement;
	}

	public boolean isNullable() {
		return nullable;
	}

	public boolean isUnique() {
		return unique;
	}

	public String getDefaulfValue() {
		return defaulfValue;
	}

	public boolean hasDefaulfValue() {
		return defaulfValue != null;
	}

	public static Column build(Field colunm) throws IllegalAccessException {
		androidx.persistence.Column annotation = colunm.getAnnotation(androidx.persistence.Column.class);
		return build(colunm, annotation);
	}

	private static Column build(Field colunm, androidx.persistence.Column annotation) throws IllegalAccessException {
		ColumnType type = annotation.type();
		boolean nullable = annotation.nullable();
		boolean unique = annotation.unique();
		return build(colunm, type, nullable, unique);
	}

	public static Column buildId(Field id) throws IllegalAccessException {
		return build(id, ColumnType.LONG, false, true);

	}

	private static Column build(Field colunm, ColumnType type, boolean nullable, boolean unique) throws IllegalAccessException {
		Column result = new Column();
		int modifiers = colunm.getModifiers();
		if (!Modifier.isStatic(modifiers)) {
			throw new PersistenceException("@Colunm " + colunm.getName() + " must be static field of " + colunm.getDeclaringClass());
		}
		if (Modifier.isPrivate(modifiers)) {
			throw new PersistenceException("@Colunm " + colunm.getName() + " must not be private field of " + colunm.getDeclaringClass());
		}
		result.name = (String) colunm.get(null);
		result.type = type;
		result.nullable = nullable;
		result.unique = unique;

		result.id = colunm.getAnnotation(Id.class) != null;
		if (result.id && !result.name.equals(Id.COLUMN_NAME)) {
			throw new IllegalArgumentException("@Id column must be named as _id");
		}

		result.autoincrement = colunm.getAnnotation(GeneratedValue.class) != null;
		if (!result.id && result.autoincrement) {
			throw new IllegalArgumentException("Cannot use autoincrement for no id column");
		}

		DefaultValue defaultValueAnnotation = colunm.getAnnotation(DefaultValue.class);
		result.defaulfValue = defaultValueAnnotation != null ? defaultValueAnnotation.value() : null;

		return result;
	}

	public static Column buildLink(Reference reference, Field column) throws IllegalAccessException {
		Column result = new Column();
		result.reference = reference;
		result.type = reference.getParent().getIdColumn().getType();
		result.name = (String) column.get(null);

		result.nullable = reference.isOptinal();

		result.id = false;
		result.unique = false;
		result.defaulfValue = null;

		return result;
	}

	public boolean isReference() {
		return reference != null;
	}

	public Reference getReference() {
		return reference;
	}

	@Override
	public String toString() {
		return name;
	}

	@Override
	public int compareTo(Column another) {
		return name.compareTo(another.name);
	}
}
